//
// RS Game Framework
// Copyright © 2009 Jedd Haberstro
// jhaberstro@gmail.com
// 
// $Id:
//

#include <rs/reflection/Reflection.hpp>
#include <rs/unittest/UnitTest.hpp>

namespace
{
    using namespace rs;
    using namespace rs::reflection;
    
    class CustomMetaData : public MetaData
    {
    public:
        
        CustomMetaData(Int32 index)
        : propertyIndex(index) {
        }
        
        Int32 propertyIndex;
    };
    
    class TestVector3f
    {
        RS_DECLARE_REFLECTION();

    private:
        Float x, y, z;
    };

    RS_DEFINE_REFLECTION_CLASS(TestVector3f)
        .BindAttribute("x", &TestVector3f::x)
        [
            AttributeProperties::FriendlyName("X Component") +
            AttributeProperties::Description("X Component description") +
            AttributeProperties::Custom("Property Index", new CustomMetaData(0))
        ]
        .BindAttribute("y", &TestVector3f::y)
        [
            AttributeProperties::FriendlyName("Y Component") +
            AttributeProperties::Description("Y Component description") +
            AttributeProperties::Custom("Property Index", new CustomMetaData(1))
        ]
        .BindAttribute("z", &TestVector3f::z)
        [
            AttributeProperties::FriendlyName("Z Component") +
            AttributeProperties::Description("Z Component description") +
            AttributeProperties::Custom("Property Index", new CustomMetaData(2))
        ];
        
        
    
    RS_TEST_CASE(rs::reflection, Attributes)
    {
        TestVector3f vec;
        
        Class const& classRecord = ReflectionCenter::GetReflectionCenter().GetClassRecord("TestVector3f");//vec.GetClassRecord();
        RS_ASSERT(3 == classRecord.GetAttributeCount(), "wrong number of fields returned");
        RS_ASSERT(std::strcmp("x", classRecord.GetAttribute(0)->GetName()) == 0, "attribute property name");
        RS_ASSERT(std::strcmp("y", classRecord.GetAttribute(1)->GetName()) == 0, "attribute property name");
        RS_ASSERT(std::strcmp("z", classRecord.GetAttribute(2)->GetName()) == 0, "attribute property name");
        RS_ASSERT(classRecord.GetAttributeViaName("x"), "attribute should exist");
        RS_ASSERT(std::strcmp("x", classRecord.GetAttributeViaName("x")->GetName()) == 0, "unexpected attribute name");
        RS_ASSERT(classRecord.GetAttributeViaName("y"), "attribute should exist");
        RS_ASSERT(std::strcmp("y", classRecord.GetAttributeViaName("y")->GetName()) == 0, "unexpected attribute name");
        RS_ASSERT(classRecord.GetAttributeViaName("z"), "attribute should exist");
        RS_ASSERT(std::strcmp("z", classRecord.GetAttributeViaName("z")->GetName()) == 0, "unexpected attribute name");
        RS_ASSERT(classRecord.GetAttributeViaName("w") == 0, "attribute should not exist");
        RS_ASSERT(classRecord.GetAttributeViaName("x")->GetType() == Types::Float, "incorrect attribute type");
        RS_ASSERT(classRecord.GetAttributeViaName("y")->GetType() == Types::Float, "incorrect attribute type");
        RS_ASSERT(classRecord.GetAttributeViaName("z")->GetType() == Types::Float, "incorrect attribute type");
        
        Float value = 0.0f;
        Class::SetAttributesValue(vec, classRecord.GetAttributeViaName("x"), 1.0f);
        Class::GetAttributesValue(vec, classRecord.GetAttributeViaName("x"), value);
        RS_ASSERT(value == 1.0f, "attribute has incorrect value");
        
        Class::SetAttributesValue(vec, classRecord.GetAttributeViaName("x"), 2.0f);
        Class::GetAttributesValue(&vec, classRecord.GetAttributeViaName("x"), reinterpret_cast< char* >(&value), sizeof(Float));
        RS_ASSERT(value == 2.0f, "attribute has incorrect value");
        
        Float newValue = 10.0f;
        Class::SetAttributesValue(&vec, classRecord.GetAttributeViaName("x"), &newValue, sizeof(Float));
        Class::GetAttributesValue(vec, classRecord.GetAttributeViaName("x"), value);
        RS_ASSERT(value == newValue, "attribute has incorrect value");
        
        RS_ASSERT(std::strcmp(classRecord.GetAttributeViaName("x")->GetProperties().GetFriendlyName(), "X Component") == 0, "AttributeProperties friendly name is incorrect");
        RS_ASSERT(std::strcmp(classRecord.GetAttributeViaName("x")->GetProperties().GetDescription(), "X Component description") == 0, "AttributeProperties description is incorrect");
        RS_ASSERT(static_cast< CustomMetaData const* >(classRecord.GetAttributeViaName("x")->GetProperties().GetMetaData("Property Index").GetPointer())->propertyIndex == 0, "AttributeProperties description is incorrect");
    }
    
    RS_TEST_CASE(rs::reflection, TypeConversionsAndExtractions)
    {
        Boolean success = GetIntegral(Types::Int32, TypeQualifiers::ConstPointer, Types::Map, TypeQualifiers::ConstPointer, Types::Void, TypeQualifiers::ConstPointer) ==
            StaticGetIntegral< Types::Int32, TypeQualifiers::ConstPointer, Types::Map, TypeQualifiers::ConstPointer, Types::Void, TypeQualifiers::ConstPointer >::kValue;
        RS_ASSERT(success, "GetIntegral and StaticGetIntegral are not consistent");
        
        success = ExtractType(GetIntegral(Types::Int32)) == StaticExtractType< StaticGetIntegral< Types::Int32 >::kValue >::kType;
        RS_ASSERT(success, "ExtractType and StaticExtractType are not consistent");
        
        success = ExtractQualifier(GetIntegral(Types::Int32)) == StaticExtractQualifier< StaticGetIntegral< Types::Int32 >::kValue >::kQualifier;
        RS_ASSERT(success, "ExtractQualifier and StaticExtractQualifier are not consistent");

        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Void >::kValue >::Type, void >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Void, TypeQualifiers::Pointer >::kValue >::Type, void* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Void, TypeQualifiers::ConstPointer >::kValue >::Type, void const* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Boolean >::kValue >::Type, Boolean >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Boolean, TypeQualifiers::Pointer >::kValue >::Type, Boolean* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Boolean, TypeQualifiers::Const >::kValue >::Type, Boolean const >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Boolean, TypeQualifiers::ConstPointer >::kValue >::Type, Boolean const* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int8 >::kValue >::Type, Int8 >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int8, TypeQualifiers::Pointer >::kValue >::Type, Int8* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int8, TypeQualifiers::Const >::kValue >::Type, Int8 const >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int8, TypeQualifiers::ConstPointer >::kValue >::Type, Int8 const* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int16 >::kValue >::Type, Int16 >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int16, TypeQualifiers::Pointer >::kValue >::Type, Int16* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int16, TypeQualifiers::Const >::kValue >::Type, Int16 const >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int16, TypeQualifiers::ConstPointer >::kValue >::Type, Int16 const* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int32 >::kValue >::Type, Int32 >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int32, TypeQualifiers::Pointer >::kValue >::Type, Int32* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int32, TypeQualifiers::Const >::kValue >::Type, Int32 const >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int32, TypeQualifiers::ConstPointer >::kValue >::Type, Int32 const* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int64 >::kValue >::Type, Int64 >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int64, TypeQualifiers::Pointer >::kValue >::Type, Int64* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int64, TypeQualifiers::Const >::kValue >::Type, Int64 const >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Int64, TypeQualifiers::ConstPointer >::kValue >::Type, Int64 const* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt8 >::kValue >::Type, UInt8 >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt8, TypeQualifiers::Pointer >::kValue >::Type, UInt8* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt8, TypeQualifiers::Const >::kValue >::Type, UInt8 const >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt8, TypeQualifiers::ConstPointer >::kValue >::Type, UInt8 const* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");

        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt16 >::kValue >::Type, UInt16 >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt16, TypeQualifiers::Pointer >::kValue >::Type, UInt16* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt16, TypeQualifiers::Const >::kValue >::Type, UInt16 const >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt16, TypeQualifiers::ConstPointer >::kValue >::Type, UInt16 const* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");

        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt32 >::kValue >::Type, UInt32 >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt32, TypeQualifiers::Pointer >::kValue >::Type, UInt32* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt32, TypeQualifiers::Const >::kValue >::Type, UInt32 const >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt32, TypeQualifiers::ConstPointer >::kValue >::Type, UInt32 const* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");

        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt64 >::kValue >::Type, UInt64 >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt64, TypeQualifiers::Pointer >::kValue >::Type, UInt64* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt64, TypeQualifiers::Const >::kValue >::Type, UInt64 const >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::UInt64, TypeQualifiers::ConstPointer >::kValue >::Type, UInt64 const* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Float >::kValue >::Type, Float >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Float, TypeQualifiers::Pointer >::kValue >::Type, Float* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Float, TypeQualifiers::Const >::kValue >::Type, Float const >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Float, TypeQualifiers::ConstPointer >::kValue >::Type, Float const* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Double >::kValue >::Type, Double >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Double, TypeQualifiers::Pointer >::kValue >::Type, Double* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Double, TypeQualifiers::Const >::kValue >::Type, Double const >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");
        success = rs::meta::IsSame< ConvertToInstrinsicType< StaticGetIntegral< Types::Double, TypeQualifiers::ConstPointer >::kValue >::Type, Double const* >::Value;
        RS_ASSERT(success, "ConvertToInstrinsicType failed");

        RS_ASSERT(ConvertToQualifiedType< void >::kQualifiedType == GetIntegral(Types::Void, TypeQualifiers::None), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< void* >::kQualifiedType == GetIntegral(Types::Void, TypeQualifiers::Pointer), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< void const* >::kQualifiedType == GetIntegral(Types::Void, TypeQualifiers::ConstPointer), "ConvertToQualifiedType failed");
        
        RS_ASSERT(ConvertToQualifiedType< Boolean >::kQualifiedType == GetIntegral(Types::Boolean, TypeQualifiers::None), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Boolean* >::kQualifiedType == GetIntegral(Types::Boolean, TypeQualifiers::Pointer), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Boolean const >::kQualifiedType == GetIntegral(Types::Boolean, TypeQualifiers::Const), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Boolean const* >::kQualifiedType == GetIntegral(Types::Boolean, TypeQualifiers::ConstPointer), "ConvertToQualifiedType failed");
        
        RS_ASSERT(ConvertToQualifiedType< Int8 >::kQualifiedType == GetIntegral(Types::Int8, TypeQualifiers::None), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Int8* >::kQualifiedType == GetIntegral(Types::Int8, TypeQualifiers::Pointer), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Int8 const >::kQualifiedType == GetIntegral(Types::Int8, TypeQualifiers::Const), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Int8 const* >::kQualifiedType == GetIntegral(Types::Int8, TypeQualifiers::ConstPointer), "ConvertToQualifiedType failed");
        
        RS_ASSERT(ConvertToQualifiedType< Int16 >::kQualifiedType == GetIntegral(Types::Int16, TypeQualifiers::None), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Int16* >::kQualifiedType == GetIntegral(Types::Int16, TypeQualifiers::Pointer), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Int16 const >::kQualifiedType == GetIntegral(Types::Int16, TypeQualifiers::Const), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Int16 const* >::kQualifiedType == GetIntegral(Types::Int16, TypeQualifiers::ConstPointer), "ConvertToQualifiedType failed");
        
        RS_ASSERT(ConvertToQualifiedType< Int32 >::kQualifiedType == GetIntegral(Types::Int32, TypeQualifiers::None), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Int32* >::kQualifiedType == GetIntegral(Types::Int32, TypeQualifiers::Pointer), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Int32 const >::kQualifiedType == GetIntegral(Types::Int32, TypeQualifiers::Const), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Int32 const* >::kQualifiedType == GetIntegral(Types::Int32, TypeQualifiers::ConstPointer), "ConvertToQualifiedType failed");
        
        RS_ASSERT(ConvertToQualifiedType< Int64 >::kQualifiedType == GetIntegral(Types::Int64, TypeQualifiers::None), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Int64* >::kQualifiedType == GetIntegral(Types::Int64, TypeQualifiers::Pointer), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Int64 const >::kQualifiedType == GetIntegral(Types::Int64, TypeQualifiers::Const), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Int64 const* >::kQualifiedType == GetIntegral(Types::Int64, TypeQualifiers::ConstPointer), "ConvertToQualifiedType failed");
        
        RS_ASSERT(ConvertToQualifiedType< UInt8 >::kQualifiedType == GetIntegral(Types::UInt8, TypeQualifiers::None), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< UInt8* >::kQualifiedType == GetIntegral(Types::UInt8, TypeQualifiers::Pointer), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< UInt8 const >::kQualifiedType == GetIntegral(Types::UInt8, TypeQualifiers::Const), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< UInt8 const* >::kQualifiedType == GetIntegral(Types::UInt8, TypeQualifiers::ConstPointer), "ConvertToQualifiedType failed");

        RS_ASSERT(ConvertToQualifiedType< UInt16 >::kQualifiedType == GetIntegral(Types::UInt16, TypeQualifiers::None), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< UInt16* >::kQualifiedType == GetIntegral(Types::UInt16, TypeQualifiers::Pointer), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< UInt16 const >::kQualifiedType == GetIntegral(Types::UInt16, TypeQualifiers::Const), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< UInt16 const* >::kQualifiedType == GetIntegral(Types::UInt16, TypeQualifiers::ConstPointer), "ConvertToQualifiedType failed");

        RS_ASSERT(ConvertToQualifiedType< UInt32 >::kQualifiedType == GetIntegral(Types::UInt32, TypeQualifiers::None), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< UInt32* >::kQualifiedType == GetIntegral(Types::UInt32, TypeQualifiers::Pointer), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< UInt32 const >::kQualifiedType == GetIntegral(Types::UInt32, TypeQualifiers::Const), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< UInt32 const* >::kQualifiedType == GetIntegral(Types::UInt32, TypeQualifiers::ConstPointer), "ConvertToQualifiedType failed");
        
        RS_ASSERT(ConvertToQualifiedType< UInt64 >::kQualifiedType == GetIntegral(Types::UInt64, TypeQualifiers::None), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< UInt64* >::kQualifiedType == GetIntegral(Types::UInt64, TypeQualifiers::Pointer), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< UInt64 const >::kQualifiedType == GetIntegral(Types::UInt64, TypeQualifiers::Const), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< UInt64 const* >::kQualifiedType == GetIntegral(Types::UInt64, TypeQualifiers::ConstPointer), "ConvertToQualifiedType failed");
        
        RS_ASSERT(ConvertToQualifiedType< Float >::kQualifiedType == GetIntegral(Types::Float, TypeQualifiers::None), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Float* >::kQualifiedType == GetIntegral(Types::Float, TypeQualifiers::Pointer), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Float const >::kQualifiedType == GetIntegral(Types::Float, TypeQualifiers::Const), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Float const* >::kQualifiedType == GetIntegral(Types::Float, TypeQualifiers::ConstPointer), "ConvertToQualifiedType failed");

        RS_ASSERT(ConvertToQualifiedType< Double >::kQualifiedType == GetIntegral(Types::Double, TypeQualifiers::None), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Double* >::kQualifiedType == GetIntegral(Types::Double, TypeQualifiers::Pointer), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Double const >::kQualifiedType == GetIntegral(Types::Double, TypeQualifiers::Const), "ConvertToQualifiedType failed");
        RS_ASSERT(ConvertToQualifiedType< Double const* >::kQualifiedType == GetIntegral(Types::Double, TypeQualifiers::ConstPointer), "ConvertToQualifiedType failed");

        RS_ASSERT(ConvertToQualifiedType< std::vector< Int32 > >::kQualifiedType == GetIntegral(Types::Int32, TypeQualifiers::None, Types::Vector, TypeQualifiers::None), "ConvertToQualifiedType failed for std::vector");
        RS_ASSERT(ConvertToQualifiedType< std::vector< Int32 >* >::kQualifiedType == GetIntegral(Types::Int32, TypeQualifiers::None, Types::Vector, TypeQualifiers::Pointer), "ConvertToQualifiedType failed for std::vector*");
        RS_ASSERT(ConvertToQualifiedType< std::vector< Int32 > const >::kQualifiedType == GetIntegral(Types::Int32, TypeQualifiers::None, Types::Vector, TypeQualifiers::Const), "ConvertToQualifiedType failed for std::vector const");
        RS_ASSERT(ConvertToQualifiedType< std::vector< Int32 > const* >::kQualifiedType == GetIntegral(Types::Int32, TypeQualifiers::None, Types::Vector, TypeQualifiers::ConstPointer), "ConvertToQualifiedType failed for std::vector const*");
        
        UInt64 qualifiedType = ConvertToQualifiedType< std::map< Int32, Int32 > >::kQualifiedType;
        RS_ASSERT(qualifiedType == GetIntegral(Types::Int32, TypeQualifiers::None, Types::Map, TypeQualifiers::None, Types::Int32, TypeQualifiers::None), "ConvertToQualifiedType failed for std::map");
        qualifiedType = ConvertToQualifiedType< std::map< Int32, Int32 >* >::kQualifiedType;
        RS_ASSERT(qualifiedType == GetIntegral(Types::Int32, TypeQualifiers::None, Types::Map, TypeQualifiers::Pointer, Types::Int32, TypeQualifiers::None), "ConvertToQualifiedType failed for std::map*");
        qualifiedType = ConvertToQualifiedType< std::map< Int32, Int32 > const >::kQualifiedType;
        RS_ASSERT(qualifiedType == GetIntegral(Types::Int32, TypeQualifiers::None, Types::Map, TypeQualifiers::Const, Types::Int32, TypeQualifiers::None), "ConvertToQualifiedType failed for std::map const");
        qualifiedType = ConvertToQualifiedType< std::map< Int32, Int32 > const* >::kQualifiedType;
        RS_ASSERT(qualifiedType == GetIntegral(Types::Int32, TypeQualifiers::None, Types::Map, TypeQualifiers::ConstPointer, Types::Int32, TypeQualifiers::None), "ConvertToQualifiedType failed for std::map const*");
    }
    
    RS_TEST_CASE(rs::reflection, Type)
    {
        Type obj(Types::Map, TypeQualifiers::Const, Types::Int32, TypeQualifiers::ConstPointer, Types::Void, TypeQualifiers::Pointer);
        
        RS_ASSERT(
            obj == Type(Types::Map, TypeQualifiers::Const, Types::Int32, TypeQualifiers::ConstPointer, Types::Void, TypeQualifiers::Pointer),
            "Type's operator== failed"
        );
        
        RS_ASSERT(
            obj != Type(Types::Map, TypeQualifiers::Const, Types::UInt32, TypeQualifiers::ConstPointer, Types::Void, TypeQualifiers::Pointer),
            "Type's operator!= failed"
        );
        
        RS_ASSERT(
            obj.ToIntegral() == GetIntegral(Types::Int32, TypeQualifiers::ConstPointer, Types::Map, TypeQualifiers::Const, Types::Void, TypeQualifiers::Pointer),
            "Type::ToIntegral() failed"
        );
        
        RS_ASSERT(
            Type(GetIntegral(Types::Int32, TypeQualifiers::ConstPointer, Types::Map, TypeQualifiers::Const, Types::Void, TypeQualifiers::Pointer)).ToIntegral() ==
                GetIntegral(Types::Int32, TypeQualifiers::ConstPointer, Types::Map, TypeQualifiers::Const, Types::Void, TypeQualifiers::Pointer),
            "Type construction from integral failed"
        );
        
        RS_ASSERT(obj.GetType() == Types::Map, "GetType() is incorrect");
        RS_ASSERT(obj.GetQualifier() == TypeQualifiers::Const, "GetQualifier() is incorrect");
        RS_ASSERT(obj.GetPrimaryType() == Types::Int32, "GetPrimaryType() is incorrect");
        RS_ASSERT(obj.GetPrimaryQualifier() == TypeQualifiers::ConstPointer, "GetPrimaryQualifier() is incorrect");
        RS_ASSERT(obj.GetElementType() == Types::Int32, "GetElementType() is incorrect");
        RS_ASSERT(obj.GetElementQualifier() == TypeQualifiers::ConstPointer, "GetElementQualifier() is incorrect");
        RS_ASSERT(obj.GetSecondaryElementType() == Types::Void, "GetSecondaryElementType() is incorrect");
        RS_ASSERT(obj.GetSecondaryElementQualifer() == TypeQualifiers::Pointer, "GetSecondaryElementQualifer() is incorrect");
    
        Boolean success = TypeFactory< std::map< Int32 const*, void* > const >::Create() == obj; 
        RS_ASSERT(success, "TypeFactory::Create() failed");
        
        success = TypeFactory< std::vector< Int32* > const >::Create() == Type(Types::Vector, TypeQualifiers::Const, Types::Int32, TypeQualifiers::Pointer);
        RS_ASSERT(success, "TypeFactory::Create() failed");
    }
}
